from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QPushButton, 
                           QLabel, QFileDialog, QProgressBar,
                           QListWidget, QHBoxLayout, QMessageBox,
                           QListWidgetItem, QStyle, QMenu)
from PyQt6.QtCore import Qt, pyqtSignal, QObject, QMimeData, QSize, QPropertyAnimation, QPoint, QTimer
from PyQt6.QtGui import (QFont, QIcon, QPixmap, QDragEnterEvent, 
                        QDropEvent, QImage, QDrag)
from utils.converter import FileConverter
import os
import threading
import subprocess
from datetime import datetime

class SignalEmitter(QObject):
    progress_signal = pyqtSignal(int)
    error_signal = pyqtSignal(str)
    complete_signal = pyqtSignal()

class ImageListWidget(QListWidget):
    """自定义图片列表控件"""
    def __init__(self, parent=None):
        super().__init__(parent)
        # 设置为图标模式
        self.setViewMode(QListWidget.ViewMode.IconMode)
        # 设置图标大小
        self.setIconSize(QSize(80, 80))
        # 设置间距
        self.setSpacing(20)  # 增加项目间距
        # 设置自动调整
        self.setResizeMode(QListWidget.ResizeMode.Adjust)
        # 设置换行
        self.setWrapping(True)
        # 设置拖拽模式为内部移动
        self.setDragDropMode(QListWidget.DragDropMode.InternalMove)
        # 设置选择模式
        self.setSelectionMode(QListWidget.SelectionMode.ExtendedSelection)
        # 设置统一的项目大小
        self.setGridSize(QSize(120, 140))  # 增加项目大小，为文字留出更多空间
        # 设置移动模式
        self.setMovement(QListWidget.Movement.Snap)  # 设置为网格对齐
        # 设置布局模式
        self.setFlow(QListWidget.Flow.LeftToRight)  # 从左到右排列
        # 设置对齐方式
        self.setLayoutMode(QListWidget.LayoutMode.Batched)  # 批量布局模式
        
        self.setStyleSheet("""
            QListWidget {
                border: 2px dashed #CCCCCC;
                border-radius: 4px;
                padding: 20px;  /* 增加内边距 */
                background: white;
            }
            QListWidget::item {
                border: 1px solid #EEEEEE;
                border-radius: 4px;
                background: white;
                color: #333333;
                margin: 5px;  /* 添加外边距 */
            }
            QListWidget::item:selected {
                background: #e0e0e0;
                border: 1px solid #2B579A;
            }
            QListWidget::item:hover {
                background: #f5f5f5;
            }
        """)

        # 添加一个计时器用于延迟刷新
        self.update_timer = QTimer(self)
        self.update_timer.setSingleShot(True)
        self.update_timer.timeout.connect(self.forceLayoutUpdate)

        # 启用右键菜单
        self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
        self.customContextMenuRequested.connect(self.show_context_menu)
        
        # 启用双击删除
        self.itemDoubleClicked.connect(self.remove_item)

    def forceLayoutUpdate(self):
        """强制更新布局和视图"""
        self.setSpacing(self.spacing())  # 触发重新布局
        self.viewport().update()  # 更新视图
        self.scrollToItem(self.currentItem())  # 确保当前项可见

    def startDrag(self, supportedActions):
        """自定义拖动事件"""
        drag = QDrag(self)
        mimeData = self.model().mimeData(self.selectedIndexes())
        drag.setMimeData(mimeData)
        
        # 设置拖动的图标
        if len(self.selectedItems()) > 0:
            item = self.selectedItems()[0]
            drag.setPixmap(item.icon().pixmap(80, 80))
        
        # 执行拖动
        drag.exec(supportedActions)

    def dragMoveEvent(self, event):
        """处理拖动过程中鼠标移动事件"""
        if not self.itemAt(event.position().toPoint()):
            super().dragMoveEvent(event)
            return

        # 获取当前鼠标位置和项目
        pos = event.position().toPoint()
        source_item = self.currentItem()
        target_item = self.itemAt(pos)

        if target_item and source_item != target_item:
            # 获取目标位置的索引
            target_row = self.row(target_item)
            source_row = self.row(source_item)
            
            # 移除源项目并在目标位置插入
            self.takeItem(source_row)
            self.insertItem(target_row, source_item)
            self.setCurrentItem(source_item)
            
            # 立即更新视图
            self.viewport().update()
            
            # 确保项目可见
            self.scrollToItem(source_item)

        event.accept()

    def dropEvent(self, event: QDropEvent):
        """处理拖放事件以更新文件顺序"""
        super().dropEvent(event)
        
        # 更新文件列表顺序
        drop_area = self.parent()
        if hasattr(drop_area, 'image_merger') and drop_area.image_merger:
            new_files = []
            for i in range(self.count()):
                item = self.item(i)
                new_files.append(item.toolTip())
            drop_area.image_merger.selected_files = new_files
        
        # 延迟刷新布局
        self.update_timer.start(100)

    def resizeEvent(self, event):
        """处理大小改变事件"""
        super().resizeEvent(event)
        # 强制更新布局
        self.forceLayoutUpdate()

    def showEvent(self, event):
        """处理显示事件"""
        super().showEvent(event)
        # 强制更新布局
        self.forceLayoutUpdate()

    def show_context_menu(self, position):
        """显示右键菜单"""
        menu = QMenu(self)
        delete_action = menu.addAction("删除")
        delete_action.triggered.connect(lambda: self.remove_item(self.itemAt(position)))
        menu.exec(self.mapToGlobal(position))

    def remove_item(self, item):
        """删除列表项"""
        if not item:
            return
            
        # 确认删除
        reply = QMessageBox.question(
            self,
            "确认删除",
            f"确定要删除文件 {item.text()} 吗？",
            QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
            QMessageBox.StandardButton.No
        )
        
        if reply == QMessageBox.StandardButton.Yes:
            # 从列表中移除
            row = self.row(item)
            item = self.takeItem(row)
            
            # 更新 ImageMerger 中的文件列表
            drop_area = self.parent()
            if hasattr(drop_area, 'image_merger') and drop_area.image_merger:
                file_path = item.toolTip()
                if file_path in drop_area.image_merger.selected_files:
                    drop_area.image_merger.selected_files.remove(file_path)
                    
                # 如果列表为空，显示提示文字
                if self.count() == 0:
                    drop_area.show_hint()
                    drop_area.image_merger.status_label.setText("")
                else:
                    drop_area.image_merger.status_label.setText(f"已删除文件：{item.text()}")
                
                # 更新合并按钮状态
                drop_area.image_merger.update_merge_button()

class DropArea(QWidget):
    """自定义拖拽区域"""
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setAcceptDrops(True)
        self.image_merger = None
        
        # 创建布局
        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        
        # 创建列表控件
        self.list_widget = ImageListWidget(self)
        
        # 创建提示标签并设置样式
        self.hint_label = QLabel("拖拽图片到此处或点击\"选择图片\"按钮")
        self.hint_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.hint_label.setStyleSheet("""
            QLabel {
                color: #999999;
                padding: 20px;
                font-size: 14px;
                background: transparent;
            }
        """)
        
        # 添加到布局
        layout.addWidget(self.list_widget)
        
        # 将提示标签设置为列表控件的子部件
        self.hint_label.setParent(self.list_widget)
        
        # 确保提示标签在列表控件中居中显示
        def resizeEvent(event):
            super(self.list_widget.__class__, self.list_widget).resizeEvent(event)
            # 调整提示标签位置
            self.hint_label.setGeometry(
                0, 0,
                self.list_widget.width(),
                self.list_widget.height()
            )
        
        # 替换列表控件的 resizeEvent
        self.list_widget.resizeEvent = resizeEvent
        
        # 设置提示标签覆盖在列表上
        self.hint_label.raise_()
    
    def set_image_merger(self, merger):
        self.image_merger = merger
        
    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls():
            event.accept()
        else:
            event.ignore()
            
    def dragMoveEvent(self, event):
        if event.mimeData().hasUrls():
            event.accept()
        else:
            event.ignore()
            
    def dropEvent(self, event):
        if event.mimeData().hasUrls():
            event.accept()
            links = []
            for url in event.mimeData().urls():
                links.append(url.toLocalFile())
            if self.image_merger:
                self.image_merger.handle_dropped_files(links)
        else:
            event.ignore()
            
    def show_hint(self):
        """显示提示文字"""
        self.hint_label.show()
    
    def hide_hint(self):
        """隐藏提示文字"""
        self.hint_label.hide()

class ImageMerger(QWidget):
    SUPPORTED_FORMATS = [
        "*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif"
    ]
    
    def __init__(self, title="图片合并", description="将多张图片合并为一个PDF文件"):
        super().__init__()
        self.title = title
        self.description = description
        self.selected_files = []  # 保存文件完整路径
        self.save_path = ""
        
        # 创建信号发射器
        self.signal_emitter = SignalEmitter()
        self.signal_emitter.progress_signal.connect(self.on_progress_update)
        self.signal_emitter.error_signal.connect(self.on_error)
        self.signal_emitter.complete_signal.connect(self.on_conversion_complete)
        
        self.init_ui()
    
    def init_ui(self):
        layout = QVBoxLayout(self)
        layout.setContentsMargins(20, 20, 20, 20)
        
        # 标题和说明
        title_label = QLabel(self.title)
        title_label.setFont(QFont("Arial", 16, QFont.Weight.Bold))
        layout.addWidget(title_label)
        
        desc_label = QLabel(self.description)
        desc_label.setStyleSheet("color: #666666;")
        layout.addWidget(desc_label)
        
        # 文件选择区域
        select_area = QHBoxLayout()
        self.select_btn = QPushButton("选择图片")
        self.select_btn.setStyleSheet("""
            QPushButton {
                background-color: #2B579A;
                color: white;
                padding: 8px 16px;
                border-radius: 4px;
            }
            QPushButton:hover {
                background-color: #1E3F7F;
            }
        """)
        self.select_btn.clicked.connect(self.select_files)
        select_area.addWidget(self.select_btn)
        
        # 添加清空按钮
        self.clear_btn = QPushButton("清空列表")
        self.clear_btn.setStyleSheet("""
            QPushButton {
                background-color: #dc3545;
                color: white;
                padding: 8px 16px;
                border-radius: 4px;
            }
            QPushButton:hover {
                background-color: #c82333;
            }
        """)
        self.clear_btn.clicked.connect(self.clear_list)
        select_area.addWidget(self.clear_btn)
        
        select_area.addStretch()
        layout.addLayout(select_area)
        
        # 使用新的拖拽区域替换原来的文件列表
        self.drop_area = DropArea(self)
        self.drop_area.set_image_merger(self)
        self.file_list = self.drop_area.list_widget  # 保持对列表的引用
        
        layout.addWidget(self.drop_area)
        
        # 保存路径选择
        save_area = QHBoxLayout()
        self.save_path_label = QLabel("未选择保存位置")
        self.save_path_label.setStyleSheet("color: #666666;")
        save_area.addWidget(self.save_path_label)
        
        self.save_btn = QPushButton("选择路径")
        self.save_btn.setStyleSheet("""
            QPushButton {
                background-color: #2B579A;
                color: white;
                padding: 8px 16px;
                border-radius: 4px;
            }
            QPushButton:hover {
                background-color: #1E3F7F;
            }
        """)
        self.save_btn.clicked.connect(self.select_save_path)
        save_area.addWidget(self.save_btn)
        layout.addLayout(save_area)
        
        # 转换进度
        self.progress_bar = QProgressBar()
        self.progress_bar.setStyleSheet("""
            QProgressBar {
                border: 1px solid #CCCCCC;
                border-radius: 4px;
                text-align: center;
            }
            QProgressBar::chunk {
                background-color: #2B579A;
            }
        """)
        self.progress_bar.hide()
        layout.addWidget(self.progress_bar)
        
        # 合并按钮
        merge_area = QHBoxLayout()
        merge_area.addStretch()
        self.merge_btn = QPushButton("合并为PDF")
        self.merge_btn.setMinimumWidth(120)
        self.merge_btn.setStyleSheet("""
            QPushButton {
                background-color: #2B579A;
                color: white;
                padding: 8px 16px;
                border-radius: 4px;
            }
            QPushButton:hover {
                background-color: #1E3F7F;
            }
            QPushButton:disabled {
                background-color: #CCCCCC;
            }
        """)
        self.merge_btn.clicked.connect(self.start_merge)
        self.merge_btn.setEnabled(False)
        merge_area.addWidget(self.merge_btn)
        layout.addLayout(merge_area)
        
        # 状态标签
        self.status_label = QLabel("")
        self.status_label.setStyleSheet("color: #666666;")
        self.status_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        layout.addWidget(self.status_label)
        
        layout.addStretch()
        
    def select_save_path(self):
        """选择保存位置"""
        path = QFileDialog.getExistingDirectory(
            self,
            "选择保存位置",
            "",
            QFileDialog.Option.ShowDirsOnly
        )
        if path:
            self.save_path = path
            self.save_path_label.setText(f"保存位置: {path}")
            self.update_merge_button()
            
    def select_files(self):
        """选择图片文件"""
        files, _ = QFileDialog.getOpenFileNames(
            self,
            "选择图片文件",
            "",
            "图片文件 (*.jpg *.jpeg *.png *.bmp)"
        )
        
        if files:
            # 如果还未设置保存路径，则设置默认保存路径为第一个文件所在目录
            if not self.save_path:
                self.save_path = os.path.dirname(files[0])
                self.save_path_label.setText(f"保存位置: {self.save_path}")
            
            # 添加新文件到列表
            for file in files:
                if file not in self.selected_files:
                    self.selected_files.append(file)
                    self.add_file_item(file)
            
            self.update_merge_button()
            self.status_label.setText(f"已添加 {len(files)} 个文件，可以开始合并")
            self.drop_area.hide_hint()
            
    def update_merge_button(self):
        """更新合并按钮状态"""
        self.merge_btn.setEnabled(
            bool(self.selected_files) and bool(self.save_path)
        )

    def start_merge(self):
        """开始合并"""
        if not self.selected_files or not self.save_path:
            return
        
        # 获取当前列表中的文件顺序
        files = []
        for i in range(self.file_list.count()):
            item = self.file_list.item(i)
            # 从 tooltip 中获取完整路径
            file_path = item.toolTip()
            files.append(file_path)
        
        # 生成带时间戳的文件名
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        output_filename = f"merged_{timestamp}.pdf"
        output_file = os.path.join(self.save_path, output_filename)
        
        self.merge_btn.setEnabled(False)
        self.select_btn.setEnabled(False)
        self.save_btn.setEnabled(False)
        self.clear_btn.setEnabled(False)
        self.progress_bar.show()
        self.progress_bar.setValue(0)
        self.status_label.setText("正在合并...")
        
        # 在新线程中执行合并
        def merge_thread():
            try:
                FileConverter.merge_images_to_pdf(
                    files,
                    output_file,
                    self.signal_emitter.progress_signal.emit
                )
                self.signal_emitter.complete_signal.emit()
            except Exception as e:
                self.signal_emitter.error_signal.emit(str(e))
        
        threading.Thread(target=merge_thread, daemon=True).start()

    def on_progress_update(self, value):
        """处理进度更新"""
        self.progress_bar.setValue(value)

    def on_error(self, error_message):
        """处理错误"""
        QMessageBox.critical(
            self,
            "合并错误",
            f"合并过程中发生错误：\n{error_message}"
        )
        self.reset_interface()

    def on_conversion_complete(self):
        """处理合并完成"""
        QMessageBox.information(
            self,
            "合并完成",
            f"图片已成功合并为PDF！\n保存位置：{self.save_path}"
        )
        self.reset_interface() 

    def clear_list(self):
        """清空文件列表"""
        self.file_list.clear()
        self.selected_files = []
        self.update_merge_button()
        self.status_label.setText("")
        self.drop_area.show_hint()  # 显示提示文字

    def reset_interface(self):
        """重置界面"""
        self.progress_bar.hide()
        self.status_label.setText("")
        self.merge_btn.setEnabled(True)
        self.select_btn.setEnabled(True)
        self.save_btn.setEnabled(True)
        self.clear_btn.setEnabled(True)
        
    def open_save_folder(self):
        """打开保存文件夹"""
        if os.path.exists(self.save_path):
            if os.name == 'nt':  # Windows
                os.startfile(self.save_path)
            else:  # Linux/Mac
                subprocess.run(['xdg-open', self.save_path]) 

    def handle_dropped_files(self, file_paths):
        """处理拖拽的文件"""
        valid_files = []
        invalid_files = []
        
        # 检查文件类型
        for file_path in file_paths:
            file_ext = os.path.splitext(file_path)[1].lower()
            if any(file_path.lower().endswith(ext.replace('*', '')) 
                  for ext in self.SUPPORTED_FORMATS):
                if file_path not in self.selected_files:
                    valid_files.append(file_path)
            else:
                invalid_files.append(os.path.basename(file_path))
        
        # 添加有效文件到列表
        for file_path in valid_files:
            self.selected_files.append(file_path)
            self.add_file_item(file_path)
            
        # 如果有效文件列表不为空且还未设置保存路径，则设置默认保存路径
        if valid_files and not self.save_path:
            default_save_path = os.path.dirname(valid_files[0])
            self.save_path = default_save_path
            self.save_path_label.setText(f"保存位置: {default_save_path}")
        
        # 如果有无效文件，显示警告
        if invalid_files:
            QMessageBox.warning(
                self,
                "不支持的文件格式",
                f"以下文件格式不受支持：\n{', '.join(invalid_files)}\n"
                f"支持的格式：{', '.join(self.SUPPORTED_FORMATS)}"
            )
        
        # 更新界面状态
        if valid_files:
            self.update_merge_button()
            self.status_label.setText(f"已添加 {len(valid_files)} 个文件，可继续添加")
            self.drop_area.hide_hint()
        
        # 如果列表为空，显示提示文字
        if not self.selected_files:
            self.drop_area.show_hint() 

    def add_file_item(self, file_path):
        """添加文件项到列表"""
        item = QListWidgetItem()
        item.setToolTip(file_path)  # 设置完整路径为提示
        
        # 创建缩略图
        pixmap = QPixmap(file_path)
        if not pixmap.isNull():
            # 如果是图片文件，创建缩略图
            pixmap = pixmap.scaled(80, 80, Qt.AspectRatioMode.KeepAspectRatio, 
                                 Qt.TransformationMode.SmoothTransformation)
        else:
            # 如果不是图片文件或无法加载，使用默认图标
            icon = self.style().standardIcon(QStyle.StandardPixmap.SP_FileIcon)
            pixmap = icon.pixmap(80, 80)
        
        item.setIcon(QIcon(pixmap))
        
        # 设置文件名为显示文本
        item.setText(os.path.basename(file_path))
        # 设置文本对齐方式
        item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
        
        self.file_list.addItem(item) 